#pragma once	

#ifndef Follows_h
#define Follows_h

#include "Standards.h"
#include "StmtTable.h"
#include "VarTable.h"
#include "Schema.h"
#include "Result.h"

/*! Follows Class */
class Follows {
	public:
		StmtTable* myST; //!< StmtTable pointer
		VarTable* myVT; //!< VarTable pointer
		Result* myResult;
		unordered_multimap<INDEX, INDEX> followsTableStmt; //!< Follows table
		unordered_multimap<INDEX, INDEX> followsTableStmtClosure; //!< Follows table
		hash_multimap<INDEX, hash_set<INDEX>> closure;
		hash_multimap<INDEX, hash_set<INDEX>> reverseClosure;

		//! Constructor (takes in the VarTable and stmtTable)
		Follows(VarTable*, StmtTable*,Result*);

		/*! 
		  A method that computes and stores the transitive closures
		*/
		void computeClosure();

		/*! 
		  A method that prints the contents of the Parent table
		*/
		void printAll();

		/*! 
		  A method that returns tuples satisfying the relation with parameters provided such as Follows(s1,s2)
		  \param DESIGN_ENTITY design-entity of s1
		  \param NAME s1
		  \param DESIGN_ENTITY design-entity of s2
		  \param NAME s2
		*/
		Schema getSynSyn(DESIGN_ENTITY,NAME,DESIGN_ENTITY,NAME);
		
		/*! 
		  A method that returns tuples satisfying the relation with parameters provided such as Follows(s1,3)
		  \param DESIGN_ENTITY design-entity of s1
		  \param NAME s1
		  \param INDEX 3
		*/
		Schema getSynInt(DESIGN_ENTITY,NAME,INDEX);
		
		/*! 
		  A method that returns tuples satisfying the relation with parameters provided such as Follows(s1,_)
		  \param DESIGN_ENTITY design-entity of s1
		  \param NAME s1
		*/
		Schema getSynUnd(DESIGN_ENTITY,NAME);

		/*! 
		  A method that returns tuples satisfying the relation with parameters provided such as Follows(3,s2)
		  \param INDEX 3
		  \param DESIGN_ENTITY design-entity of s2
		  \param NAME s2
		*/
		Schema getIntSyn(INDEX,DESIGN_ENTITY,NAME);
		
		/*! 
		  A method that returns tuples satisfying the relation with parameters provided such as Follows(3,4)
		  \param INDEX 3
		  \param INDEX 4
		*/
		Schema getIntInt(INDEX,INDEX);
		
		/*! 
		  A method that returns tuples satisfying the relation with parameters provided such as Follows(3,_)
		  \param INDEX 3
		*/
		Schema getIntUnd(INDEX);

		/*! 
		  A method that returns tuples satisfying the relation with parameters provided such as Follows(_,3)
		  \param INDEX 3
		*/
		Schema getUndInt(INDEX);
		
		/*! 
		  A method that returns tuples satisfying the relation with parameters provided such as Follows(_,s2)
		  \param DESIGN_ENTITY design-entity of s2
		  \param NAME s2
		*/
		Schema getUndSyn(DESIGN_ENTITY,NAME);
		
		/*! 
		  A method that returns tuples satisfying the relation with parameters provided such as Follows(_,_) 
		*/
		Schema getUndUnd();


		//.........................................

				//...Closure...

		/*! 
		  A method that returns tuples satisfying the relation with parameters provided such as Follows(s1,s2)
		  \param DESIGN_ENTITY design-entity of s1
		  \param NAME s1
		  \param DESIGN_ENTITY design-entity of s2
		  \param NAME s2
		*/
		Schema getSynSynClosure(DESIGN_ENTITY,NAME,DESIGN_ENTITY,NAME);
		
		/*! 
		  A method that returns tuples satisfying the relation with parameters provided such as Follows(s1,3)
		  \param DESIGN_ENTITY design-entity of s1
		  \param NAME s1
		  \param INDEX 3
		*/
		Schema getSynIntClosure(DESIGN_ENTITY,NAME,INDEX);
		
		/*! 
		  A method that returns tuples satisfying the relation with parameters provided such as Follows(s1,_)
		  \param DESIGN_ENTITY design-entity of s1
		  \param NAME s1
		*/
		Schema getSynUndClosure(DESIGN_ENTITY,NAME);

		/*! 
		  A method that returns tuples satisfying the relation with parameters provided such as Follows(3,s2)
		  \param INDEX 3
		  \param DESIGN_ENTITY design-entity of s2
		  \param NAME s2
		*/
		Schema getIntSynClosure(INDEX,DESIGN_ENTITY,NAME);
		
		/*! 
		  A method that returns tuples satisfying the relation with parameters provided such as Follows(3,4)
		  \param INDEX 3
		  \param INDEX 4
		*/
		Schema getIntIntClosure(INDEX,INDEX);
		
		/*! 
		  A method that returns tuples satisfying the relation with parameters provided such as Follows(3,_)
		  \param INDEX 3
		*/
		Schema getIntUndClosure(INDEX);

		/*! 
		  A method that returns tuples satisfying the relation with parameters provided such as Follows(_,3)
		  \param INDEX 3
		*/
		Schema getUndIntClosure(INDEX);
		
		/*! 
		  A method that returns tuples satisfying the relation with parameters provided such as Follows(_,s2)
		  \param DESIGN_ENTITY design-entity of s2
		  \param NAME s2
		*/
		Schema getUndSynClosure(DESIGN_ENTITY,NAME);
		
		/*! 
		  A method that returns tuples satisfying the relation with parameters provided such as Follows(_,_) 
		*/
		Schema getUndUndClosure();


		//..........................
		/*! 
		  A method that inserts tuple <x,y> into Follows table signifying y follows x
		  \param INDEX Follower
		  \param INDEX Followed
		*/
		void set(INDEX, INDEX);
	private:
		int count; //!< Size of Follows table
};

#endif